iT邦幫忙

2021 iThome 鐵人賽

DAY 6
2

這個 hook 可以讓我們用類似 redux 用 reducer、action、dispatch 操作 state。

useReducer 適合較複雜的 state,因為我們可以將狀態的改變統一放在 reducer 去做管理,像 useState 的狀態改變就會分散在不同的函式裡面。

useState 的底層其實是用 useReducer 實踐的

語法

const [state, dispatch] = useReducer(reducer, initialState, initStateFn);

  • useReducer 第一個參數用來設定變更 state 的規則,特定的 action 時如何更新 state
  • useReducer 第二個參數是初始化的 state
  • useReducer 第三個參數是初始化 state 的函式,非必要的參數
  • dispatch 用來觸發 action

第三個參數要怎麼使用? 這個在 React 官網有提到,撰寫一個會 return 初始化 state 的函式,放到第三個參數,可以避免重新去建立初始 state。

如果把初始化 state 的函式包在 useReducer 第二個參數,會在每次 render 呼叫,所以要避免。

function createInitialState(username) {
  // init state
}

function TodoList({ username }) {
  const [state, dispatch] = useReducer(reducer, username, createInitialState);
  // ...

優點

dispatch 不會隨著 rerender 而重新分配記憶體位置,在作為 props 傳入到 child component 中時也可以不用擔心沒有 useMemo 而造成 re-render 的問題

缺點

  1. useReducer 無法存取 global store
  2. useReducer 沒有 middleware,不能像 Redux 能用 thunk 或 saga 來做 data fetching、處理 side effect

範例

import React, { useReducer } from "react";

// 初始化 state
const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    case "reset":
      return { count: (state.count = 0) };
    default:
      return { count: state.count };
  }
}

export default function App() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      Count: {state.count}
      <br />
      <br />
      <button onClick={() => dispatch({ type: "increment" })}>Increment</button>
      <button onClick={() => dispatch({ type: "decrement" })}>Decrement</button>
      <button onClick={() => dispatch({ type: "reset" })}>Reset</button>
    </div>
  );
}

本篇範例程式在以下連結:

範例程式(Codesandbox)


上一篇
Day5-React Hook 篇-認識 useContext
下一篇
Day7-在認識 useMemo 前,先認識 React.memo
系列文
用30天更加認識 React.js 這個好朋友33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言